{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 单个数据预处理\n",
    "\n",
    "为构建我们的本地知识库，我们需要对以多种类型存储的本地文档进行处理，读取本地文档并通过前文描述的 Embedding 方法将本地文档的内容转化为词向量来构建向量数据库。接下来以一些实际示例入手，来讲解如何对本地文档进行处理。\n",
    "## 数据读取\n",
    "将知识库源数据放置在../../data_base/knowledge_db 目录下\n",
    "\n",
    "**PDF文档为例**  \n",
    "可以使用 LangChain 的 PyMuPDFLoader 来读取知识库的 PDF 文件。PyMuPDFLoader 是 PDF 解析器中速度最快的一种，结果会包含 PDF 及其页面的详细元数据，并且每页返回一个文档。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.document_loaders.pdf import PyMuPDFLoader\n",
    "\n",
    "# 创建一个 PyMuPDFLoader Class 实例，输入为待加载的 pdf 文档路径\n",
    "loader = PyMuPDFLoader(\"../data_base/knowledge_path/VMAX-S/ZXVMAX-S（V6.23）产品描述（上网日志业务）.pdf\")\n",
    "\n",
    "# 调用 PyMuPDFLoader Class 的函数 load 对 pdf 文件进行加载\n",
    "pdf_pages = loader.load()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "文档加载后储存在 `pdf_pages` 变量中:\n",
    "- `pdf_pages` 的变量类型为 `List`\n",
    "- 打印 `pdf_pages` 的长度可以看到 pdf 一共包含多少页"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "载入后的变量类型为：<class 'list'>， 该 PDF 一共包含 29 页\n"
     ]
    }
   ],
   "source": [
    "print(f\"载入后的变量类型为：{type(pdf_pages)}，\",  f\"该 PDF 一共包含 {len(pdf_pages)} 页\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`pdf_pages` 中的每一元素为一个文档，变量类型为 `langchain_core.documents.base.Document`, 文档变量类型包含两个属性\n",
    "- `page_content` 包含该文档的内容。\n",
    "- `meta_data` 为文档相关的描述性数据。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "每一个元素的类型：<class 'langchain_core.documents.base.Document'>.\n",
      "------\n",
      "该文档的描述性数据：{'producer': 'Apache FOP Version 2.6', 'creator': 'DITA Open Toolkit', 'creationdate': '2023-05-23T21:45:33+08:00', 'source': '../data_base/knowledge_path/VMAX-S/ZXVMAX-S（V6.23）产品描述（上网日志业务）.pdf', 'file_path': '../data_base/knowledge_path/VMAX-S/ZXVMAX-S（V6.23）产品描述（上网日志业务）.pdf', 'total_pages': 29, 'format': 'PDF 1.4', 'title': '目录', 'author': '', 'subject': '', 'keywords': '', 'moddate': '', 'trapped': '', 'modDate': '', 'creationDate': \"D:20230523214533+08'00'\", 'page': 20}\n",
      "------\n",
      "查看该文档的内容:\n",
      "7可靠性设计容错能力\n",
      "ZXVMAX-S通过对关键软件资源的定时检测、实时任务监控、存储保护、数据校验、操作日志信息保存等手段，可有效地防止小软件故障对系统所造成的冲击，提高了软件系统的容错能力（即软件错误情况下的自愈能力）。故障监视及处理\n",
      "ZXVMAX-S具备自动检测与诊断系统软硬件故障的功能，可对故障硬件实施自动隔离、倒换、重新启动、重新加载等处理。满足漏洞扫描为了避免存在安全漏洞使在网设备受外部攻击，需要使系统满足主流安全漏洞扫描工具的要求。\n",
      "ZXVMAX-S满足Nessus和CD工具安全漏洞扫描的要求。\n",
      "7.3 数据可靠性\n",
      "ZXVMAX-S产品在不同分层架构下的数据都可以确保数据可靠和可恢复。采集层采集层运行环境部署采用冗余磁盘阵列设计，在服务器损坏、单一硬盘故障等场景下，通过替换故障硬件后即可工作，数据不会丢失。同时，系统支持数据补充采集，确保系统数据连续性。存储共享层存储共享层的MPP数据库，根据需要都设置了多个冗余备份，单一节点的损坏不会影响整系统的运行，也不会导致数据丢失。在替换损坏硬件后，系统能自动进行数据冗余备份的补全和负载均衡。存储共享层的MPP数据库，设计运行在冗余磁盘阵列上，并且是具备双控制器的外置磁阵，在确保性能的同时避免了磁阵数据丢失。应用分析层应用分析层操作系统和软件模块都部署在冗余磁盘阵列上，系统软件、配置数据等信息在单一磁盘损坏，主机故障等情形下都不会丢失。\n",
      "7.4 组网可靠性\n",
      "ZXVMAX-S产品根据需要，可以通过交换机冗余备份，各主机网络的以太网隧道冗余备份，实现对业务和设备的保护。在单一交换机故障时，备用交换机会及时启用，避免业务中断。在单一的网络传输故障时，备用的传输链路仍然生效，也能避免业务中断。\n",
      "SJ-20220623151803-017|2023-03-30（R1.0）\n",
      "17\n"
     ]
    }
   ],
   "source": [
    "pdf_page = pdf_pages[20]\n",
    "print(f\"每一个元素的类型：{type(pdf_page)}.\", \n",
    "    f\"该文档的描述性数据：{pdf_page.metadata}\", \n",
    "    f\"查看该文档的内容:\\n{pdf_page.page_content}\", \n",
    "    sep=\"\\n------\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 假设环境中缺少 NLTK 数据包中的 punkt 资源，这是 NLTK 库中用于分词的一个重要组件。解决这个问题的方法是按照报错信息中提到的步骤下载并安装 punkt 资源。\n",
    "# import nltk\n",
    "# nltk.download('punkt', quiet=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据清洗"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们期望知识库的数据尽量是有序的、优质的、精简的，因此我们要删除低质量的、甚至影响理解的文本数据。  \n",
    "可以看到上文中读取的pdf文件不仅将一句话按照原文的分行添加了换行符`\\n`，也在原本两个符号中间插入了`\\n`，我们可以使用正则表达式匹配并删除掉`\\n`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**处理单个page**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "\n",
    "# 预编译正则表达式（提升效率）\n",
    "linebreak_pattern = re.compile(\n",
    "    r'(?<![\\\\u4e00-\\\\u9fff])\\n(?![\\\\u4e00-\\\\u9fff])',  # 负向断言匹配非中文环境换行\n",
    "    flags=re.DOTALL\n",
    ")\n",
    "space_pattern = re.compile(r'[ 　]+')  # 匹配半角/全角空格\n",
    "special_chars = ['•', '▪', '▫', '▶', '®', '©']  # 可扩展的干扰符号列表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'7可靠性设计容错能力\\nZXVMAX-S通过对关键软件资源的定时检测、实时任务监控、存储保护、数据校验、操作日志信息保存等手段，可有效地防止小软件故障对系统所造成的冲击，提高了软件系统的容错能力（即软件错误情况下的自愈能力）。故障监视及处理\\nZXVMAX-S具备自动检测与诊断系统软硬件故障的功能，可对故障硬件实施自动隔离、倒换、重新启动、重新加载等处理。满足漏洞扫描为了避免存在安全漏洞使在网设备受外部攻击，需要使系统满足主流安全漏洞扫描工具的要求。\\nZXVMAX-S满足Nessus和CD工具安全漏洞扫描的要求。\\n7.3\\xa0数据可靠性\\nZXVMAX-S产品在不同分层架构下的数据都可以确保数据可靠和可恢复。\\uf06c采集层采集层运行环境部署采用冗余磁盘阵列设计，在服务器损坏、单一硬盘故障等场景下，通过替换故障硬件后即可工作，数据不会丢失。同时，系统支持数据补充采集，确保系统数据连续性。\\uf06c存储共享层存储共享层的MPP数据库，根据需要都设置了多个冗余备份，单一节点的损坏不会影响整系统的运行，也不会导致数据丢失。在替换损坏硬件后，系统能自动进行数据冗余备份的补全和负载均衡。存储共享层的MPP数据库，设计运行在冗余磁盘阵列上，并且是具备双控制器的外置磁阵，在确保性能的同时避免了磁阵数据丢失。\\uf06c应用分析层应用分析层操作系统和软件模块都部署在冗余磁盘阵列上，系统软件、配置数据等信息在单一磁盘损坏，主机故障等情形下都不会丢失。\\n7.4\\xa0组网可靠性\\nZXVMAX-S产品根据需要，可以通过交换机冗余备份，各主机网络的以太网隧道冗余备份，实现对业务和设备的保护。在单一交换机故障时，备用交换机会及时启用，避免业务中断。在单一的网络传输故障时，备用的传输链路仍然生效，也能避免业务中断。\\nSJ-20220623151803-017|2023-03-30（R1.0）\\n17'"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pdf_page.page_content = re.sub(\n",
    "        linebreak_pattern,\n",
    "        lambda m: m.group().replace('\\n', ''),\n",
    "        pdf_page.page_content\n",
    "    )\n",
    "    \n",
    "# 2. 批量清理特殊符号\n",
    "for char in special_chars:\n",
    "        pdf_page.page_content = pdf_page.page_content.replace(char, '')\n",
    "    \n",
    "# 3. 安全删除空格（保留URL等特殊场景）\n",
    "pdf_page.page_content = space_pattern.sub('', pdf_page.page_content)\n",
    "\n",
    "pdf_page.page_content"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 文档分割\n",
    "\n",
    "由于单个文档的长度往往会超过模型支持的上下文，导致检索得到的知识太长超出模型的处理能力，因此，在构建向量知识库的过程中，我们往往需要对文档进行分割，将单个文档按长度或者按固定的规则分割成若干个 chunk，然后将每个 chunk 转化为词向量，存储到向量数据库中。\n",
    "\n",
    "在检索时，我们会以 chunk 作为检索的元单位，也就是每一次检索到 k 个 chunk 作为模型可以参考来回答用户问题的知识，这个 k 是我们可以自由设定的。\n",
    "\n",
    "Langchain 中文本分割器都根据 `chunk_size` (块大小)和 `chunk_overlap` (块与块之间的重叠大小)进行分割。\n",
    "\n",
    "![image.png](../../assets/rag8.png)\n",
    "\n",
    "* chunk_size 指每个块包含的字符或 Token （如单词、句子等）的数量\n",
    "\n",
    "* chunk_overlap 指两个块之间共享的字符数量，用于保持上下文的连贯性，避免分割丢失上下文信息"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Langchain 提供多种文档分割方式，区别在怎么确定块与块之间的边界、块由哪些字符/token组成、以及如何测量块大小**\n",
    "\n",
    "- RecursiveCharacterTextSplitter(): 按字符串分割文本，递归地尝试按不同的分隔符进行分割文本。\n",
    "- CharacterTextSplitter(): 按字符来分割文本。\n",
    "- MarkdownHeaderTextSplitter(): 基于指定的标题来分割markdown 文件。\n",
    "- TokenTextSplitter(): 按token来分割文本。\n",
    "- SentenceTransformersTokenTextSplitter(): 按token来分割文本\n",
    "- Language(): 用于 CPP、Python、Ruby、Markdown 等。\n",
    "- NLTKTextSplitter(): 使用 NLTK（自然语言工具包）按句子分割文本。\n",
    "- SpacyTextSplitter(): 使用 Spacy按句子的切割文本。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "''' \n",
    "* RecursiveCharacterTextSplitter 递归字符文本分割\n",
    "RecursiveCharacterTextSplitter 将按不同的字符递归地分割(按照这个优先级[\"\\n\\n\", \"\\n\", \" \", \"\"])，\n",
    "    这样就能尽量把所有和语义相关的内容尽可能长时间地保留在同一位置\n",
    "RecursiveCharacterTextSplitter需要关注的是4个参数：\n",
    "\n",
    "* separators - 分隔符字符串数组\n",
    "* chunk_size - 每个文档的字符数量限制\n",
    "* chunk_overlap - 两份文档重叠区域的长度\n",
    "* length_function - 长度计算函数\n",
    "'''\n",
    "#导入文本分割器\n",
    "from langchain.text_splitter import RecursiveCharacterTextSplitter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 知识库中单段文本长度\n",
    "CHUNK_SIZE = 512\n",
    "\n",
    "# 知识库中相邻文本重合长度\n",
    "OVERLAP_SIZE = 50"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用递归字符文本分割器\n",
    "text_splitter = RecursiveCharacterTextSplitter(\n",
    "    chunk_size=CHUNK_SIZE,\n",
    "    chunk_overlap=OVERLAP_SIZE\n",
    ")\n",
    "# text_splitter.split_text(pdf_page.page_content[0:1000])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "切分后的文件数量：55\n"
     ]
    }
   ],
   "source": [
    "split_docs = text_splitter.split_documents(pdf_pages)\n",
    "print(f\"切分后的文件数量：{len(split_docs)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'10\\xa0遵循标准与要求\\n本章包含如下主题：\\n\\uf06c 运维标准\\n23\\n\\uf06c 安全标准\\n23\\n10.1\\xa0运维标准\\nZXVMAX-S产品符合TMF以下标准：GB923，GB921，GB917，GB922，TR148，TR149\\n10.2\\xa0安全标准\\nZXVMAX-S产品符合以下安全标准：\\n\\uf06c\\nCIS 安全加固标准\\n\\uf06c\\nISO/IEC 15408：信息技术安全评估通用准则（CC，Common Criteria，对应的国标是GB/\\nT 18336）\\n\\uf06c\\nGB/T 18336：信息技术 安全技术 信息技术安全性评估准则\\n\\uf06c\\nUL 60950-1：ed.2/CSA-C22.2 No.60950-1-07:ed.2\\nSJ-20220623151803-017 | 2023-03-30（R1.0）\\n23'"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "split_docs[50].page_content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "切分后的字符数（可以用来大致评估 token 数）：18934\n"
     ]
    }
   ],
   "source": [
    "print(f\"切分后的字符数（可以用来大致评估 token 数）：{sum([len(doc.page_content) for doc in split_docs])}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "注：如何对文档进行分割，其实是数据处理中最核心的一步，其往往决定了检索系统的下限。但是，如何选择分割方式，往往具有很强的业务相关性——针对不同的业务、不同的源数据，往往需要设定个性化的文档分割方式。因此，在本章，我们仅简单根据 chunk_size 对文档进行分割。对于有兴趣进一步探索的读者，欢迎阅读我们第三部分的项目示例来参考已有的项目是如何进行文档分割的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 批量数据预处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "批量处理文件夹中所有文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['../data_base/knowledge_path/VMAX-S/ZXVMAX-S（V6.23）产品描述（5GC业务）.pdf', '../data_base/knowledge_path/VMAX-S/ZXVMAX-S（V6.20.80.02）告警处理.pdf', '../data_base/knowledge_path/VMAX-S/ZXVMAX-S（V6.23）产品描述（语音业务）.pdf', '../data_base/knowledge_path/VMAX-S/ZXVMAX-S（V6.23）产品描述（数据业务）.pdf', '../data_base/knowledge_path/VMAX-S/ZXVMAX-S（V6.20.80.02）故障管理概述.pdf', '../data_base/knowledge_path/VMAX-S/ZXVMAX-S（V6.23）产品描述（端到端业务）.pdf', '../data_base/knowledge_path/VMAX-S/ZXVMAX-S（V6.23）产品描述（上网日志业务）.pdf']\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "\n",
    "# 获取folder_path下所有文件路径，储存在file_paths里\n",
    "file_paths = []\n",
    "folder_path = '../data_base/knowledge_path/VMAX-S'\n",
    "for root, dirs, files in os.walk(folder_path):\n",
    "    for file in files:\n",
    "        file_path = os.path.join(root, file)\n",
    "        file_paths.append(file_path)\n",
    "print(file_paths)\n",
    "\n",
    "from langchain.document_loaders.pdf import PyMuPDFLoader\n",
    "# from langchain.document_loaders.markdown import UnstructuredMarkdownLoader\n",
    "\n",
    "# 遍历文件路径并把实例化的loader存放在loaders里\n",
    "loaders = []\n",
    "\n",
    "for file_path in file_paths:\n",
    "    file_type = file_path.split('.')[-1]\n",
    "    if file_type == 'pdf':\n",
    "        loaders.append(PyMuPDFLoader(file_path))\n",
    "    else:\n",
    "        print(f\"Unsupported file type: {file_type} for file {file_path}\")\n",
    "\n",
    "\n",
    "# 下载文件并存储到text\n",
    "# 加载所有文档内容到 texts\n",
    "texts = []\n",
    "for loader in loaders:\n",
    "    texts.extend(loader.load())  # 关键步骤：初始化 texts\n",
    "\n",
    "\n",
    "# 作数据清洗\n",
    "# 修改后的数据清洗部分（替换原始代码中对应段落）\n",
    "import re\n",
    "\n",
    "# 预编译正则表达式（提升效率）\n",
    "linebreak_pattern = re.compile(\n",
    "    r'(?<![\\\\u4e00-\\\\u9fff])\\n(?![\\\\u4e00-\\\\u9fff])',  # 负向断言匹配非中文环境换行\n",
    "    flags=re.DOTALL\n",
    ")\n",
    "space_pattern = re.compile(r'[ 　]+')  # 匹配半角/全角空格\n",
    "special_chars = ['•', '▪', '▫', '▶', '®', '©']  # 可扩展的干扰符号列表\n",
    "\n",
    "# 替换原始代码中的清洗循环\n",
    "for text in texts:\n",
    "    # 1. 清理非中文环境换行\n",
    "    text.page_content = re.sub(\n",
    "        linebreak_pattern,\n",
    "        lambda m: m.group().replace('\\n', ''),\n",
    "        text.page_content\n",
    "    )\n",
    "    \n",
    "    # 2. 批量清理特殊符号\n",
    "    for char in special_chars:\n",
    "        text.page_content = text.page_content.replace(char, '')\n",
    "    \n",
    "    # 3. 安全删除空格（保留URL等特殊场景）\n",
    "    text.page_content = space_pattern.sub('', text.page_content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "''' \n",
    "* RecursiveCharacterTextSplitter 递归字符文本分割\n",
    "RecursiveCharacterTextSplitter 将按不同的字符递归地分割(按照这个优先级[\"\\n\\n\", \"\\n\", \" \", \"\"])，\n",
    "    这样就能尽量把所有和语义相关的内容尽可能长时间地保留在同一位置\n",
    "RecursiveCharacterTextSplitter需要关注的是4个参数：\n",
    "\n",
    "* separators - 分隔符字符串数组\n",
    "* chunk_size - 每个文档的字符数量限制\n",
    "* chunk_overlap - 两份文档重叠区域的长度\n",
    "* length_function - 长度计算函数\n",
    "'''\n",
    "#导入文本分割器\n",
    "from langchain.text_splitter import RecursiveCharacterTextSplitter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 知识库中单段文本长度\n",
    "CHUNK_SIZE = 512\n",
    "\n",
    "# 知识库中相邻文本重合长度\n",
    "OVERLAP_SIZE = 50"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用递归字符文本分割器\n",
    "text_splitter = RecursiveCharacterTextSplitter(\n",
    "    chunk_size=CHUNK_SIZE,\n",
    "    chunk_overlap=OVERLAP_SIZE\n",
    ")\n",
    "# text_splitter.split_text(text.page_content[0:1000])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "切分后的文件数量：891\n"
     ]
    }
   ],
   "source": [
    "split_docs = text_splitter.split_documents(texts)\n",
    "print(f\"切分后的文件数量：{len(split_docs)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "切分后的字符数（可以用来大致评估 token 数）：319269\n"
     ]
    }
   ],
   "source": [
    "print(f\"切分后的字符数（可以用来大致评估 token 数）：{sum([len(doc.page_content) for doc in split_docs])}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'ZXVMAX-S多维价值分析系统告警处理可能原因通过DAPManager查看具体原因并参照其建议处理处理步骤通过DAPManager查看具体原因并参照其建议处理\\n1.120114010081ResourceManager进程MEM使用率告警描述\\nResourceManager进程MEM使用率告警级别可变（对于不同值，会产生相应级别的告警）可能原因内存配置无法满足业务需求。内存使用率达到上限。处理步骤\\n1.修改告警阈值，当内存使用率小于或等于阈值时，告警恢复；\\n2.对节点进行内存扩容；\\n3.收集故障信息，通过菜单日志搜索yarn服务日志，联系技术支持分析日志；\\n1.121114020039NodeManager进程本地空间使用率告警描述\\nNodeManager进程本地空间使用率告警级别可变（对于不同值，会产生相应级别的告警）可能原因\\nYarn空间使用率超过空间告警阈值处理步骤\\n1.修改告警阈值，当空间使用率小于或等于阈值时，告警恢复；\\n2.对节点进行磁盘扩容\\n66\\nSJ-20220623151803-011|2022-06-20（R1.0）'"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "split_docs[300].page_content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "env_rag",
   "language": "python",
   "name": "env_rag"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
